package com.xwn.utils.core;

import org.apache.http.util.ByteArrayBuffer;

import com.xwn.utils.core.T.CipherUtils;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;

/**
 * @Author duandw
 * @Date 2019/12/31 17:42
 **/
public class CryptUtilsImpl {
    private static int HEAD_LENGTH = 128;

    public CryptUtilsImpl() {
    }

    public static String decryptWithHeaderByIosAes(File srcFile, String charsetName) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, IOException {
        return new String(decryptWithHeaderByIosAes(readFileAsByteArray(srcFile)), charsetName == null ? "UTF-8" : charsetName);
    }

    public static void decryptWithHeaderByIosAes(File srcFile, File destFile) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, IOException {
        writeFile(destFile, decryptWithHeaderByIosAes(readFileAsByteArray(srcFile)));
    }

    public static void encryptWithHeaderByIosAes(File srcFile, File destFile) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, IOException {
        byte[] bytes = encryptWithHeaderByIosAes(readFileAsByteArray(srcFile));
        writeFile(destFile, bytes);
    }

    public static void encryptWithHeaderByIosAes(String content, File destFile, String charsetName) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, IOException {
        writeFile(destFile, encryptWithHeaderByIosAes(content.getBytes(charsetName == null ? "UTF-8" : charsetName)));
    }

    private static byte[] readFileAsByteArray(File f) throws IOException {
        FileInputStream is = null;

        try {
            is = new FileInputStream(f);
            ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(1024);
            byte[] b = new byte[512];

            int len;
            while((len = is.read(b)) > 0) {
                byteArrayBuffer.append(b, 0, len);
            }

            byte[] var5 = byteArrayBuffer.toByteArray();
            return var5;
        } finally {
            is.close();
        }
    }

    private static void writeFile(File f, byte[] bytes) throws IOException {
        f.setWritable(true);
        FileOutputStream outputStream = null;

        try {
            outputStream = new FileOutputStream(f);
            outputStream.write(bytes);
            outputStream.flush();
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }

        }

    }

    public static byte[] decryptWithHeaderByIosAes(byte[] in) throws NoSuchPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
        if (in != null && in.length >= HEAD_LENGTH + 16) {
            byte[] head = new byte[HEAD_LENGTH];
            int bodyLen = in.length - HEAD_LENGTH;
            byte[] body = new byte[bodyLen];
            System.arraycopy(in, 63, head, 0, 16);
            System.arraycopy(in, HEAD_LENGTH, body, 0, bodyLen);
            byte[] decryptByIosAES = CipherUtilsImpl.byteDecryptByIosAES(CipherUtils.getKey(), body);
            byte[] md5 = getMd5(decryptByIosAES);

            for(int i = 0; i < md5.length; ++i) {
                if (md5[i] != head[i]) {
                    throw new RuntimeException(MessageFormat.format("Decrypt bytes With wrong Header, m:{0},, h:{1}, please check the data source!", byte2hex(md5), byte2hex(head)));
                }
            }

            return decryptByIosAES;
        } else {
            throw new RuntimeException("The byte-array 'in' is illegal!");
        }
    }

    public static byte[] encryptWithHeaderByIosAes(byte[] in) throws NoSuchPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
        byte[] body = CipherUtilsImpl.byteEncryptByIosAES(CipherUtils.getKey(), in);
        byte[] all = new byte[HEAD_LENGTH + body.length];

        for(int i = 0; i < 128; ++i) {
            all[i] = (byte)AESDataEncodeUtilsImpl.AverageRandom(0, 255);
        }

        byte[] head = getMd5(in);
        System.arraycopy(head, 0, all, 63, head.length);
        System.arraycopy(body, 0, all, HEAD_LENGTH, body.length);
        return all;
    }

    public static byte[] getMd5(byte[] bytes) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(bytes, 0, bytes.length);
        return md.digest();
    }

    private static String byte2hex(byte[] bytes) {
        StringBuffer sb = new StringBuffer(bytes.length * 2);

        for(int n = bytes.length - 1; n >= 0; --n) {
            String tmp = Integer.toHexString(bytes[n] & 255);
            if (tmp.length() == 1) {
                sb.append("0");
            }

            sb.append(tmp);
        }

        return sb.toString().toUpperCase();
    }
}
